
/*--------------------------------------------------------------------------

自分にも使える回復アイテム


■概要
　範囲の設定が射程になっている回復アイテムを自分自身を対象として使えます。
　ステート付与アイテムとステート回復アイテム、瞬間移動アイテム、ドーピングアイテムでも使えるようになりました。

■使用法
　本スクリプトを入れてアイテムにカスパラ{isSelfOK:1}を追加すると、
　範囲の設定が射程になっている回復アイテムを自分自身を対象として使う事が出来るようになります。

■カスタマイズ
　・自分を対象として回復する時は運動を一つだけ表示するようにしたい
　　→「var SelfHealDispOnlyLeftWindow = false;」のfalseをtrueに書き換えてください。

　・敵や同盟のユニットも、範囲：射程の回復アイテムを自分自身を対象として使いたい
　　→「var isSelfHealEnemy = false;」のfalseをtrueに書き換えてください。

　　　※ステート付与、ステート回復アイテムを同盟軍に使わせたい場合、フィルタに同盟軍を含めないといけないようです
　　　　（フィルタが自軍のみだと、同盟軍は自軍ユニットに対してのみ使用しました）
　　　　また、ステート付与アイテムとステート回復アイテムは使うかどうかの計算時にスコアが低くなりがちなので、
　　　　設定してもAIが使わない事があります

　・道具、杖の射程を+1するスキルを使いたい
　　※範囲攻撃アイテムや範囲回復アイテムは対応していません
　　『共通処理』
　　　スキル種別：カスタムでスキルを作成し、キーワードに「ItemRangeExtend」をセットします。

　　『道具の射程を+1するスキルの場合』
　　　スキルのカスタムパラメータに{itemRangeExtend:1}を入れると、そのスキルを所持するユニットはアイテムの射程が1伸びます
　　　（itemRangeExtendの後ろの数値分伸びるので、2とか3とかにすると+2とか+3になります）

　　『杖の射程を+1するスキルの場合』
　　　スキルのカスタムパラメータに{wandRangeExtend:1}を入れると、そのスキルを所持するユニットは杖の射程が1伸びます
　　　（wandRangeExtendの後ろの数値分伸びるので、2とか3とかにすると+2とか+3になります）
　　　※マーキング処理はこの動作に対応していません。杖の方はなるべく使わない方が良いと思います

　　『杖と道具の射程を+1するスキルの場合』
　　　スキルのカスタムパラメータに{itemRangeExtend:1, wandRangeExtend:1}を入れると、
　　　そのスキルを所持するユニットは杖とアイテムの射程が1伸びます
　　　※マーキング処理はこの動作に対応していません。杖の方はなるべく使わない方が良いと思います


修正内容
16/10/01　新規作成
16/10/02　自分を対象として回復する場合にウィンドウが表示されないのを修正
          また自分を対象として回復する際には左側ウィンドウだけ表示する設定を追加
16/10/02b 会話選択時にエラーが出るバグを修正
17/03/03  敵（同盟）ユニットも、自分を対象として回復アイテムが使えるよう修正
17/11/06  ステート付与アイテムとステート回復アイテムでも設定可能とした
          ※ステート付与アイテムとステート回復アイテムはスコアが低くなりがちなので、設定してもAIが使わない事があります
            また同盟軍の場合フィルタで同盟にもチェックが入っていないと同盟軍同士では使ってくれないようです
17/11/06b ステート回復アイテムの情報確認時に範囲も表示するようにした
20/12/02  瞬間移動アイテムでも設定可能とした
21/04/25  1.227対応（1.226以前も従来通り動作します）
21/06/26  アイテムの射程を増やせるカスタムスキルをテスト実装（改修箇所の関係で範囲攻撃アイテムには効果が出ません）
22/07/21  ドーピングアイテムでも設定可能とした
22/10/12  射程：全域の回復アイテムでも設定可能とした（回復アイテム以外は未対応です）
23/04/30  1.281対応
23/08/05  競合対策で処理を変更
24/11/10  競合対策で処理を変更


■対応バージョン
　SRPG Studio Version:1.303_1


■規約
・利用はSRPG Studioを使ったゲームに限ります。
・商用・非商用問いません。フリーです。
・加工等、問題ありません。どんどん改造してください。
・クレジット明記無し　OK
・再配布、転載　OK
・wiki掲載　OK
・SRPG Studio利用規約は遵守してください。

--------------------------------------------------------------------------*/

(function() {
//----------------------------
// 設定
//----------------------------
// 自分を回復する時、左側ウィンドウだけ表示するか（true:左側ウィンドウだけ表示、false:左右のウィンドウを表示）
var SelfHealDispOnlyLeftWindow = false;

// 敵ユニット、同盟ユニットも範囲：射程の回復アイテムを自分自身を対象として使うか（true：使う　false:使わない）
var isSelfHealEnemy            = false;

// 杖もしくは道具の射程を増やすカスタムスキルのキーワード
var ItemRangeExtendSkillWord = 'ItemRangeExtend';




//----------------------------
// RecoveryItemSelectionクラス
//----------------------------
var alias1 = RecoveryItemSelection.isPosSelectable;
RecoveryItemSelection.isPosSelectable= function() {
		var result = alias1.call(this);

		if( typeof this._item.custom.isSelfOK === 'number' ) {
			return this._posSelector.getSelectorTarget2(true) !== null;
		}

		return result;
}




//----------------------------
// RecoveryItemAvailabilityクラス
//----------------------------
var alias2 = RecoveryItemAvailability.isPosEnabled;
RecoveryItemAvailability.isPosEnabled= function(unit, item, x, y) {
		var targetUnit;
		var result = alias2.call(this, unit, item, x, y);

		if( result == true) {
			return true;
		}
		
		targetUnit = PosChecker.getUnitFromPos(x, y);
		if (targetUnit !== null ) {
			if( typeof item.custom.isSelfOK === 'number' && targetUnit === unit ) {
				if (FilterControl.isBestUnitTypeAllowed(unit.getUnitType(), targetUnit.getUnitType(), item.getFilterFlag())) {
					return this._isCondition(unit, targetUnit, item) && this.isItemAllowed(unit, targetUnit, item);
				}
			}
		}
		return false;
}


var alias03 = RecoveryItemAvailability._checkAll;
RecoveryItemAvailability._checkAll= function(unit, item) {
		var targetUnit;
		var result = alias03.call(this, unit, item);
		
		if( result === true) {
			return true;
		}
		
		if( typeof item.custom.isSelfOK === 'number' ) {
			if( this._isCondition(unit, unit, item) && this.isItemAllowed(unit, unit, item)) {
				return true;
			}
		}
		
		return result;
}




//----------------------------
// StateItemSelectionクラス
//----------------------------
var alias10 = StateItemSelection.isPosSelectable;
StateItemSelection.isPosSelectable= function() {
		var targetUnit;
		var result = alias10.call(this);

		if( typeof this._item.custom.isSelfOK === 'number' ) {
			return this._posSelector.getSelectorTarget2(true) !== null;
		}

		return result;
}




//----------------------------
// StateItemAvailabilityクラス
//----------------------------
var alias11 = StateItemAvailability.isPosEnabled;
StateItemAvailability.isPosEnabled= function(unit, item, x, y) {
		var targetUnit;
		var result = alias11.call(this, unit, item, x, y);

		if( result == true) {
			return true;
		}
		
		targetUnit = PosChecker.getUnitFromPos(x, y);
		if (targetUnit !== null ) {
			if( typeof item.custom.isSelfOK === 'number' && targetUnit === unit ) {
				if (FilterControl.isBestUnitTypeAllowed(unit.getUnitType(), targetUnit.getUnitType(), item.getFilterFlag())) {
					return this._isCondition(unit, targetUnit, item) && this.isItemAllowed(unit, targetUnit, item);
				}
			}
		}
		return false;
}




//----------------------------
// StateRecoveryItemSelectionクラス
//----------------------------
var alias12 = StateRecoveryItemSelection.isPosSelectable;
StateRecoveryItemSelection.isPosSelectable= function() {
		var targetUnit;
		var result = alias12.call(this);

		if( typeof this._item.custom.isSelfOK === 'number' ) {
			targetUnit = this._posSelector.getSelectorTarget2(true);
			if (targetUnit === null) {
				return false;
			}
			
			return StateControl.isStateRecoverable(targetUnit, this._item.getStateRecoveryInfo().getStateGroup());
		}

		return result;
}




//----------------------------
// StateRecoveryItemAvailabilityクラス
//----------------------------
var alias13 = StateRecoveryItemAvailability.isPosEnabled;
StateRecoveryItemAvailability.isPosEnabled= function(unit, item, x, y) {
		var targetUnit;
		var result = alias13.call(this, unit, item, x, y);

		if( result == true) {
			return true;
		}
		
		targetUnit = PosChecker.getUnitFromPos(x, y);
		if (targetUnit !== null ) {
			if( typeof item.custom.isSelfOK === 'number' && targetUnit === unit ) {
				if (FilterControl.isBestUnitTypeAllowed(unit.getUnitType(), targetUnit.getUnitType(), item.getFilterFlag())) {
					return this._isCondition(unit, targetUnit, item) && this.isItemAllowed(unit, targetUnit, item);
				}
			}
		}
		return false;
}




//------------------
// IndexArrayクラス
//------------------
var indexCheckUnit = null;	// BaseItemAvailability._checkMulti関数、BaseItemSelection.setUnitSelection関数
							// BaseItemSelection.setUnitSelection関数でセットされる
var alias15 = IndexArray.createIndexArray;
IndexArray.createIndexArray= function(x, y, item) {
		var obj, rangeValue, rangeType;
		var startRange = 1;
		var endRange = 1;
		
		if( item !== null && !item.isWeapon() ) {
			if( typeof ItemRangeControl.getRangeObject !== 'undefined' ) {
				obj = ItemRangeControl.getRangeObject(item);
				rangeValue = obj.rangeValue;
				rangeType = obj.rangeType;
			}
			else {
				if (item.getItemType() === ItemType.TELEPORTATION && item.getRangeType() === SelectionRangeType.SELFONLY) {
					rangeValue = item.getTeleportationInfo().getRangeValue();
					rangeType = item.getTeleportationInfo().getRangeType();
				}
				// 1.281対応
				else if( root.getScriptVersion() >= 1281 && item.getItemType() === ItemType.QUICK && 
						 item.getRangeType() === SelectionRangeType.SELFONLY && item.getQuickInfo().getValue() === QuickValue.ONE) {
					// アイテム効果が「1ユニット」に設定されている場合、ユニットを選択できるように変更
					rangeValue = 1;
					rangeType = SelectionRangeType.MULTI;
				}
				else {
					rangeValue = item.getRangeValue();
					rangeType = item.getRangeType();
				}
			}
			
			if (rangeType === SelectionRangeType.MULTI) {
				endRange = rangeValue;
				if( typeof item.custom.isSelfOK === 'number' ) {
					startRange = 0;
				}
				
				// アイテムの射程を拡張
				// ※IndexArray.createIndexArray関数にはユニットを関数で引き渡せないので変数indexCheckUnitにセットしている
				//   （呼び出し側は呼び出し前にindexCheckUnitへユニットをセットし、呼び出し後indexCheckUnit=nullで消して下さい）
				if( indexCheckUnit != null ) {
					endRange += this.getRangeExtendValueEx(indexCheckUnit, item);
				}
				
				return this.getBestIndexArray(x, y, startRange, endRange);
			}
		}
		
		return alias15.apply(this, arguments);
}


// アイテムの射程を拡張してる部分（ここから）
IndexArray.getRangeExtendValueEx= function(unit, item) {
		var skill, isWand;
		var rangeValue = 0;
		
		if (item === null) {
			return 0;
		}
		
		if (unit == null) {
			return 0;
		}
		
		if (item.isWeapon()) {
			return 0;
		}
		
		skill = SkillControl.getPossessionCustomSkill(unit, ItemRangeExtendSkillWord);
		if( skill === null ) {
			return 0;
		}
		
		if( typeof isWandTypeExtra !== 'undefined' ) {
			isWand = WandChecker.isWand(item);
		}
		else {
			isWand = item.isWand();
		}
		
		// 杖の場合
		if( isWand === true ) {
			rangeValue = skill.custom.wandRangeExtend;
		}
		// 道具の場合
		else {
			rangeValue = skill.custom.itemRangeExtend;
		}
		
		if( typeof rangeValue !== 'number' ) {
			return 0;
		}
		
		return rangeValue;
}
// アイテムの射程を拡張してる部分（ここまで）




//------------------
// PosSelectorクラス
//------------------
PosSelector.getSelectorTarget2= function(isIndexArray) {
		var child;
		var unit = this._posCursor.getUnitFromCursor();
		
		if (this._unit === unit) {
			if (this._isFusionIncluded) {
				child = FusionControl.getFusionChild(unit);
				if (child !== null) {
					return child;
				}
			}
		}
		
		// カーソルの位置にユニットが存在し、さらに範囲内に存在するかを確認する場合
		if (unit !== null && isIndexArray) {
			// 範囲内に存在しない場合はnullを返す
			if (!IndexArray.findUnit(this._indexArray, unit)) {
				unit = null;
			}
		}
		
		return unit;
}


PosSelector.setNewTarget= function() {
		if( this._item == null || typeof this._item.custom.isSelfOK !== 'number' ) {
			this._posMenu.changePosTarget(this.getSelectorTarget(true));
		}
		else {
			this._posMenu.changePosTarget(this.getSelectorTarget2(true));
		}
}
	


var alias20 = PosSelector._setPosMenu;
PosSelector._setPosMenu= function(unit, item, type) {
		alias20.call(this, unit, item, type);
		this._item = item;
}




//------------------
// PosMenuクラス
//------------------
var alias25 = PosMenu.drawWindowManager;
PosMenu.drawWindowManager= function() {
		// アイテム使用時、SelfHealDispOnlyLeftWindowがtrueかつ対象が自分なら右ウィンドウを消す
		if( this._item != null && !this._item.isWeapon() ){
			this._posWindowRight._isWindowEnabled = true;
			
			if( SelfHealDispOnlyLeftWindow === true && this._unit === this._currentTarget ) {
				this._posWindowRight._isWindowEnabled = false;
			}
		}
		
		alias25.call(this);
}




//------------------
// CombinationCollector.Itemクラス
//------------------
if( isSelfHealEnemy == true ) {
	CombinationCollector.Item._setUnitRangeCombination= function(misc, filter, rangeMetrics) {
		var i, j, indexArray, list, targetUnit, targetCount, score, combination, aggregation;
		var unit = misc.unit;
		var filterNew = this._arrangeFilter(unit, filter);
		var listArray = this._getTargetListArray(filterNew, misc);
		var listCount = listArray.length;
		var isSelfOK = 0;
		
		if (misc.item !== null && !misc.item.isWeapon()) {
			aggregation = misc.item.getTargetAggregation();

			// 回復アイテムのカスパラにisSelfOKがあれば自分も回復対象に含める
			if( typeof misc.item.custom.isSelfOK === 'number' ) {
				rangeMetrics.startRange = 0;
				isSelfOK = misc.item.custom.isSelfOK;
			}
		}
		else if (misc.skill !== null) {
			aggregation = misc.skill.getTargetAggregation();
		}
		else {
			aggregation = null;
		}
		
		for (i = 0; i < listCount; i++) {
			list = listArray[i];
			targetCount = list.getCount();
			for (j = 0; j < targetCount; j++) {
				targetUnit = list.getData(j);
				if (unit === targetUnit && isSelfOK == 0) {
					continue;
				}
				
				if (aggregation !== null && !aggregation.isCondition(targetUnit)) {
					continue;
				}
				
				score = this._checkTargetScore(unit, targetUnit);
				if (score < 0) {
					continue;
				}
				
				// targetUnit(自分ではなく相手)の現在位置をベースに、一連の範囲を求める
				indexArray = IndexArray.createRangeIndexArray(targetUnit.getMapX(), targetUnit.getMapY(), rangeMetrics);
				
				misc.targetUnit = targetUnit;
				misc.indexArray = indexArray;
				misc.rangeMetrics = rangeMetrics;
				
				// 一連の範囲から、実際に移動できる位置を格納した配列を取得する
				misc.costArray = this._createCostArray(misc);
				
				if (misc.costArray.length !== 0) {
					// 移動できる位置があるため、組み合わせを作成する
					combination = this._createAndPushCombination(misc);
					combination.plusScore = score;
				}
			}
		}
	}
}




//------------------
// StateRecoveryItemInfoクラス
//------------------
var alias30 = StateRecoveryItemInfo.drawItemInfoCycle;
StateRecoveryItemInfo.drawItemInfoCycle= function(x, y) {
		alias30.call(this, x, y);
		
		// 1.227より前の場合は範囲を一番最後に描画
		if( typeof this._stateCount === 'undefined' ) {
			y += ItemInfoRenderer.getSpaceY() * (this.getInfoPartsCount() - 1);
			this.drawRange(x, y, this._item.getRangeValue(), this._item.getRangeType());
		}
}


var alias31 = StateRecoveryItemInfo.getInfoPartsCount;
StateRecoveryItemInfo.getInfoPartsCount= function() {
		var partsCount = alias31.call(this);
		
		// 1.227より前の場合は範囲を描画する為、パーツに+1
		if( typeof this._stateCount === 'undefined' ) {
			partsCount++;
		}
		
		return partsCount;
}




//----------------------------
// TeleportationItemSelectionクラス
//----------------------------
var alias40 = TeleportationItemSelection.isPosSelectable;
TeleportationItemSelection.isPosSelectable= function() {
		var mode = this.getCycleMode();

		if (mode === ItemTeleportationSelectMode.TARGETSELECT && typeof this._item.custom.isSelfOK === 'number' ) {
			return this._posSelector.getSelectorTarget2(true) !== null;
		}

		return alias40.call(this);
}


TeleportationItemSelection._moveTargetSelect= function() {
		var targetUnit;
		var result = this._posSelector.movePosSelector();
		
		if (result === PosSelectorResult.SELECT) {
			if (this.isPosSelectable()) {
//				this._targetUnit = this._posSelector.getSelectorTarget(false);
				targetUnit = this._posSelector.getSelectorTarget(false);
				if (targetUnit !== null) {
					this._targetUnit = targetUnit;
				}
				this._changePosSelect();
			}
		}
		else if (result === PosSelectorResult.CANCEL) {
			this._isSelection = false;
			return MoveResult.END;
		}
		
		return MoveResult.CONTINUE;
}




//----------------------------
// TeleportationItemAvailabilityクラス
//----------------------------
var alias41 = TeleportationItemAvailability.isPosEnabled;
TeleportationItemAvailability.isPosEnabled= function(unit, item, x, y) {
		var targetUnit;
		var result = alias41.call(this, unit, item, x, y);

		if( result == true) {
			return true;
		}
		
		targetUnit = PosChecker.getUnitFromPos(x, y);
		if (targetUnit !== null ) {
			if( typeof item.custom.isSelfOK === 'number' && targetUnit === unit ) {
				if (FilterControl.isBestUnitTypeAllowed(unit.getUnitType(), targetUnit.getUnitType(), item.getFilterFlag())) {
					return this._isCondition(unit, targetUnit, item) && this.isItemAllowed(unit, targetUnit, item);
				}
			}
		}
		return false;
}




//-------------------------------------------
// BaseItemAvailabilityクラス
//-------------------------------------------
var alias50 = BaseItemAvailability._checkMulti;
BaseItemAvailability._checkMulti= function(unit, item) {
		indexCheckUnit = unit;
		
		var result = alias50.call(this, unit, item);
		
		indexCheckUnit = null;
		
		return result;
}




//-------------------------------------------
// BaseItemSelectionクラス
//-------------------------------------------
var alias60 = BaseItemSelection.setUnitSelection;
BaseItemSelection.setUnitSelection= function() {
		indexCheckUnit = this._unit;
		
		alias60.call(this);
		
		indexCheckUnit = null;
}


var alias61 = BaseItemSelection.setUnitSelection;
BaseItemSelection.setPosSelection= function() {
		indexCheckUnit = this._unit;
		
		alias61.call(this);
		
		indexCheckUnit = null;
}




//----------------------------
// DopingItemSelectionクラス
//----------------------------
var alias70 = DopingItemSelection.isPosSelectable;
DopingItemSelection.isPosSelectable= function() {
		var targetUnit;
		var result = alias70.call(this);

		if( typeof this._item.custom.isSelfOK === 'number' ) {
			return this._posSelector.getSelectorTarget2(true) !== null;
		}

		return result;
}




//----------------------------
// DopingItemAvailabilityクラス
//----------------------------
var alias71 = DopingItemAvailability.isPosEnabled;
DopingItemAvailability.isPosEnabled= function(unit, item, x, y) {
		var targetUnit;
		var result = alias71.call(this, unit, item, x, y);

		if( result == true) {
			return true;
		}
		
		targetUnit = PosChecker.getUnitFromPos(x, y);
		if (targetUnit !== null ) {
			if( typeof item.custom.isSelfOK === 'number' && targetUnit === unit ) {
				if (FilterControl.isBestUnitTypeAllowed(unit.getUnitType(), targetUnit.getUnitType(), item.getFilterFlag())) {
					return this._isCondition(unit, targetUnit, item) && this.isItemAllowed(unit, targetUnit, item);
				}
			}
		}
		return false;
}


})();